// NFC_11 [OpenGL Spheres Applet].nova // Using namespace declarations. using Library.Math; using Library.NFC; using Library.OpenGL; // The applet class. class SpheresApplet : Applet, IRun { // Applet data members. private bool active; private int mouseX, mouseY; private bool mouseButtonDown; private double spinX, spinY; // THe view matrix. private Matrix4d viewMatrix; // An array to hold the spheres. private GLObject[] spheres; // The number of spheres. private uint numSpheres; // Animation flags. private bool animationEnabled, blurEnabled; // Sphere attributes. private double angleX, angleY, angleZ; private double separation; private double animationSpeed; private double transparency; // The window's OpenGL rendering context. private RenderingContext renderingContext; // Application class's "main" function. public static void main( String[] args ) { // Output the keyboard contols. Stream.write( "Keyboard controls:\n" + " a = toggle animation\n" + " b = toggle motion blur\n" ); // Create a new applet window with a new applet instance. AppletWindow window = new AppletWindow( new SpheresApplet( ), "NFC_11 [OpenGL Spheres Applet]", 640, 480 ); // Show the applet window. window.show( true ); // Process the applet window's events. window.processEvents( ); } // Initialize the applet. public virtual void onInit( ) { // Initialize the applet's data members. mouseX = mouseY = 0; spinX = spinY = 0; active = true; mouseButtonDown = false; viewMatrix = new Matrix4d( ); numSpheres = 4; animationEnabled = true; blurEnabled = false; angleX = angleY = angleZ = 0; separation = 30.0; animationSpeed = 0.7; transparency = 0.8; // Create an OpenGL rendering context. renderingContext = OpenGL.createContext( graphics ); // Make the new rendering context the current one. OpenGL.makeCurrent( graphics, renderingContext ); // Initialize the context. OpenGL.glClearColor( 1.0f, 1.0f, 1.0f, 0.0f ); OpenGL.glShadeModel( OpenGL.GL_FLAT ); OpenGL.glClearDepth( 1.0 ); OpenGL.glEnable( OpenGL.GL_DEPTH_TEST ); float[ ] light_diffuse = { 1.0f, 1.0f, 1.0f, 0.0f }; float[ ] light_specular = { 1.0f, 1.0f, 1.0f, 0.0f }; float[ ] mat_specular = { 1.0f, 1.0f, 1.0f, 1.0f }; float[ ] mat_shininess = { 50.0f }; OpenGL.glLightfv( OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, light_diffuse ); OpenGL.glLightfv( OpenGL.GL_LIGHT0, OpenGL.GL_SPECULAR, light_specular ); OpenGL.glMaterialfv( OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_SPECULAR, mat_specular ); OpenGL.glMaterialfv( OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_SHININESS, mat_shininess ); OpenGL.glColorMaterial( OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_DIFFUSE ); OpenGL.glEnable( OpenGL.GL_COLOR_MATERIAL ); OpenGL.glEnable( OpenGL.GL_LIGHT0 ); OpenGL.glEnable( OpenGL.GL_LIGHTING ); OpenGL.glEnable( OpenGL.GL_NORMALIZE ); OpenGL.glEnable( OpenGL.GL_CULL_FACE ); OpenGL.glEnable( OpenGL.GL_BLEND ); OpenGL.glBlendFunc( OpenGL.GL_SRC_ALPHA, OpenGL.GL_ONE_MINUS_SRC_ALPHA ); OpenGL.glClearAccum( 1.0, 1.0, 1.0, 1.0 ); OpenGL.glClear( OpenGL.GL_ACCUM_BUFFER_BIT ); // Create the applet's spheres. createSpheres( ); // Create a new thread to update the applet. Thread updateThread = new Thread( this, null ); // Start the thread. updateThread.start( ); } // Create the spheres for the scene. private void createSpheres( ) { // Initialize to an empty array. spheres = new GLObject[ numSpheres ]; // Iterate through the number of spheres. for ( uint loopIndex = 0; loopIndex < numSpheres; loopIndex++ ) { // Create a sphere display list. uint displayList = OpenGL.glGenLists( 1 ); OpenGL.glNewList( displayList, OpenGL.GL_COMPILE ); Sphere.drawSphere( ); OpenGL.glEndList( ); // Create a new GLObject with the display list. // The display list is deleted when the object is deleted. spheres[ loopIndex ] = new GLObject( displayList ); } // Set the colours of the spheres. spheres[ 0 ].setColour( 1.0, 0.1, 0.0, transparency ); // Red. spheres[ 1 ].setColour( 0.0, 1.0, 0.0, transparency ); // Green. spheres[ 2 ].setColour( 0.0, 0.3, 1.0, transparency ); // Blue. spheres[ 3 ].setColour( 1.0, 1.0, 0.2, transparency ); // Yellow. } // Run the applet (the update thread's method). public virtual Object run( Object arg ) { // Run while the active flag is set. while ( active ) { // Check if the mouse button is up. if ( mouseButtonDown == false ) { // Spin the scene. rotateScene( ); } // Repaint the applet. repaint( ); } // Set the current OpenGL context to null. OpenGL.makeCurrent( null, null ); // Delete the OpenGL context. OpenGL.deleteContext( renderingContext ); return null; } // On key down event handler. public virtual void onKeyDown( uint key ) { // Check for the "a" key. if ( key == KeyReference.VK_A ) { // Toggle the animation flag. animationEnabled = !animationEnabled; } // Check for the "b" key. if ( key == KeyReference.VK_B ) { // Toggle the blur flag. blurEnabled = !blurEnabled; if ( blurEnabled ) { OpenGL.glClear( OpenGL.GL_ACCUM_BUFFER_BIT ); } } } // On mouse button down event handler. public virtual void onMouseButtonDown( int button ) { // Check for the left mouse button index. if ( button == 0 ) { // Update the state of the left mouse button. mouseButtonDown = true; // Stop the cube from spinning. spinX = spinY = 0; } } // On mouse button up event handler. public virtual void onMouseButtonUp( int button ) { // Check for the left mouse button index. if ( button == 0 ) { // Update the state of the left mouse button. mouseButtonDown = false; } } // On mouse move event handler. public virtual void onMouseMove( int posX, int posY ) { // Update the state of the left mouse button. mouseButtonDown = getKeyState( KeyReference.VK_LBUTTON ); // Check if the mouse button is pressed. if ( mouseButtonDown ) { spinX = (double)( posY - mouseY ) / 2.0; spinY = (double)( posX - mouseX ) / 2.0; // Orientate the scene. rotateScene( ); } mouseX = posX; mouseY = posY; } // On size event handler. public virtual void onSize( int sizeX, int sizeY ) { // Prevent a divide by zero error. if ( sizeY == 0 ) { // Set the height equal to one. sizeY = 1; } // Reset the current viewport. OpenGL.glViewport( 0, 0, sizeX, sizeY ); // Select the projection matrix. OpenGL.glMatrixMode( OpenGL.GL_PROJECTION ); // Reset the projection matrix. OpenGL.glLoadIdentity( ); // Calculate the aspect ratio of the window. OpenGL.gluPerspective( 45.0, (double)sizeX / (double)sizeY, 10.0, 1000.0 ); // Select the modelview matrix. OpenGL.glMatrixMode( OpenGL.GL_MODELVIEW ); // Reset the modelview matrix. OpenGL.glLoadIdentity( ); if ( blurEnabled ) { OpenGL.glClear( OpenGL.GL_ACCUM_BUFFER_BIT ); } } // On paint event handler. public virtual void onPaint( ) { // Clear the buffers. OpenGL.glClear( OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT ); // Reset the current matrix. OpenGL.glLoadIdentity( ); // Move into the scene. OpenGL.glTranslatef( 0.0f, 0.0f, -100.0f ); // Check the animation flag. if ( animationEnabled ) { // Increment the animation angles. angleX += 0.5 * animationSpeed; angleY += 0.6 * animationSpeed; angleZ += 0.7 * animationSpeed; } ////////////////////////////////////////////// // Calculate the common sphere orientation. // ////////////////////////////////////////////// Matrix3d orientationMatrix = new Matrix3d( ); orientationMatrix.rotateX( -angleX ); orientationMatrix.rotateY( -angleY ); orientationMatrix.rotateZ( -angleZ ); // Create a new animation matrix. Matrix4d animationMatrix = new Matrix4d( ); // Rotate the animation by the view matrix. animationMatrix.multiply( viewMatrix ); // Initialize the animation matrix. animationMatrix.rotateX( angleX ); animationMatrix.rotateY( angleY ); animationMatrix.rotateZ( angleZ ); // Create a matrix to position each sphere. Matrix4d sphereMatrix = new Matrix4d( ); double[] position = new double[ 3 ]; // Render the red sphere. sphereMatrix.multiply( animationMatrix ); sphereMatrix.translate( separation, 0, 0 ); sphereMatrix.transform( position ); spheres[ 0 ].setPosition( position ); spheres[ 0 ].setOrientation( orientationMatrix ); // Render the green sphere. sphereMatrix.loadIdentity( ); sphereMatrix.multiply( animationMatrix ); sphereMatrix.translate( -separation, 0, 0 ); position = { 0, 0, 0 }; sphereMatrix.transform( position ); spheres[ 1 ].setPosition( position ); spheres[ 1 ].setOrientation( orientationMatrix ); // Render the blue sphere. sphereMatrix.loadIdentity( ); sphereMatrix.multiply( animationMatrix ); sphereMatrix.translate( 0, separation, 0 ); position = { 0, 0, 0 }; sphereMatrix.transform( position ); spheres[ 2 ].setPosition( position ); spheres[ 2 ].setOrientation( orientationMatrix ); // Render the yellow sphere. sphereMatrix.loadIdentity( ); sphereMatrix.multiply( animationMatrix ); sphereMatrix.translate( 0, -separation, 0 ); position = { 0, 0, 0 }; sphereMatrix.transform( position ); spheres[ 3 ].setPosition( position ); spheres[ 3 ].setOrientation( orientationMatrix ); // Create a shallow copy of the spheres array. GLObject[] spheresCopy = spheres.copy( ); // Depth sort the copied array of spheres into the most distant sphere first. // The most distant sphere has the lowest z axis value in OpenGL. // This is needed to ensure the correct rendering of the sphere transparencies. for ( uint i = 1; i < numSpheres; i++ ) { for ( uint j = 0; j < numSpheres - 1; j++ ) { // Get the z positions of the current two objects. double z1 = spheresCopy[ j ].getPositionZ( ); double z2 = spheresCopy[ j + 1 ].getPositionZ( ); // Compare the current two z axis values. if ( z1 > z2 ) { // Reorder the current two objects in increasing value of z. GLObject hold = spheresCopy[ j ]; spheresCopy[ j ] = spheresCopy[ j + 1 ]; spheresCopy[ j + 1 ] = hold; } } } // Iterate through all of the spheres. for ( uint loopIndex = 0; loopIndex < numSpheres; loopIndex++ ) { // Render the current sphere. spheresCopy[ loopIndex ].render( ); } // Apply motion blur if enabled. if ( blurEnabled ) { float q = 0.92f; OpenGL.glAccum( OpenGL.GL_MULT, q ); // Reduce (scale) the accum buffer. OpenGL.glAccum( OpenGL.GL_ACCUM, 1 - q ); // Add a fraction of the back buffer to the accum buffer. OpenGL.glAccum( OpenGL.GL_RETURN, 1 ); // Copy the accum buffer to the back buffer (current). } // Swap the window's OpenGL buffers. OpenGL.swapBuffers( graphics ); } // On close event handler. public virtual void onClose( ) { // Set the active flag to false to stop the rendering thread. active = false; } // Rotate the scene. private void rotateScene( ) { // Create a local rotation matrix. Matrix4d rotationMatix = new Matrix4d( ); // Rotate the rotation matrix. rotationMatix.rotateX( spinX ); rotationMatix.rotateY( spinY ); // Pre-multiply the scene's matrix with the rotation matrix. viewMatrix = rotationMatix.multiply( viewMatrix ); } } class Sphere { public static void drawSphere( ) { // Create a new GLUqradric object. GLUquadric quadObject = OpenGL.gluNewQuadric( ); OpenGL.gluQuadricDrawStyle( quadObject, OpenGL.GLU_FILL ); OpenGL.gluQuadricNormals( quadObject, OpenGL.GLU_FLAT ); OpenGL.gluSphere( quadObject, 20.0, 10, 5 ); OpenGL.gluDeleteQuadric( quadObject ); } }